feat(guard): audit the REQUIRED fuzz context's target list, not only the advisory one (#406) - #409
Merged
Merged
Conversation
…visory one (#406) REQ-GUARD-GATE-EVIDENCE-002 (h) added check_fuzz_targets.py to stop the fuzz target list drifting from its fuzz/Cargo.toml [[bin]] declaration. It audited the wrong one of two lists. `fuzz-nightly.yml`'s matrix (what the tool compared) is ADVISORY — its job name is templated, so it can never be a required context. `ci.yml`'s fuzz-smoke job, which hand-writes each harness as a `cargo fuzz run <target>` step, IS the required context (`Fuzz smoke (60s/target)`) and was compared against nothing. Add a [[bin]] plus a nightly matrix entry but forget the fuzz-smoke step and the tool reported `All 4 declared fuzz targets are run` while the REQUIRED gate fuzzed 3 of 4, green, forever. Extending the nightly `- target:` regex to ci.yml does not work — the targets sit as the positional of a `cargo fuzz run` command inside `run:` steps. A second extractor (smoke_targets) parses them, scoped to the fuzz-smoke: job block and skipping full-line comments so a `fuzz run` string in prose cannot poison the scan, dropping the +toolchain token, value flags with their argument (so --target <triple> is not read as a harness), and libfuzzer args after `--`; a command not resolving to exactly one positional is a broken scan (exit 2). The declaration is now audited against BOTH lists, worst exit wins. Self-test grows to 18 rows, including the #406 acceptance criterion (a [[bin]] absent from fuzz-smoke exits 1), the comment-poisoning regression, and a real-tree row asserting the committed ci.yml is clean under both audits. REQ-GUARD-FUZZ-SMOKE-001 + TEST-GUARD-FUZZ-SMOKE (with runnable steps and satisfies/verifies links) record it. The human-scoped REQ-GUARD-GATE-EVIDENCE-002 is left untouched. Set equality proves DECLARATION parity, not execution — a continue-on-error/if:false leg still counts as run; that is a distinct obligation left to a successor. Closes #406. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rivet verification gate✅ 20/20 passed
Filter: Failed artifacts(none) Updated automatically by |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merged
avrabe
added a commit
that referenced
this pull request
Aug 8, 2026
Bump workspace + vscode-spar to v0.36.0; promote REQ-GUARD-FUZZ-SMOKE-001 to verified (release v0.36.0). Ships the #409 fuzz-target guardrail fix that audits the required fuzz-smoke context's target list.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
tools/check_fuzz_targets.py(added for REQ-GUARD-GATE-EVIDENCE-002 (h)) audited the wrong one of two fuzz target lists. This teaches it to audit the one that actually gates merges.fuzz-nightly.yml'smatrix.include, what the tool compared. Its job name is templated (Fuzz ${{ matrix.target }}), so bycheck_required_contexts.py's rules it can never be a required context.ci.yml'sfuzz-smokejob (Fuzz smoke (60s/target), in.github/required-contexts.txt), which hand-writes each harness as acargo +nightly fuzz run <target>step. It was compared against nothing.So the covered list was advisory and the uncovered list blocked merges. Add a
[[bin]]plus a nightly matrix entry but forget thefuzz-smokestep, and the tool reportedAll 4 declared fuzz targets are runwhile the required gate fuzzed 3 of 4, green, forever (#406) — the requirement's own defect shape one level up.How
The nightly's
- target:regex can't be reused: the fuzz-smoke targets sit as the positional of acargo … fuzz runcommand insiderun:steps. A second extractor (smoke_targets) parses them, scoped to thefuzz-smoke:job block and skipping full-line comments so afuzz runstring in prose can't poison the scan. It drops the+toolchaintoken, value-taking flags with their argument (so--target <triple>is never read as a harness), and the libfuzzer args after--; a command not resolving to exactly one positional is a broken scan (exit 2), never a silently dropped leg. The declaration is now asserted against both lists; the worst exit wins.The comment-scoping is not hypothetical: an intermediate version scanned the whole file, matched this PR's own guard-step comment (
cargo … fuzz run … <target>), and turned the requiredRivet validate (artifacts)context red. The clean-room pass caught it before it shipped; the fix is block scoping plus a real-tree self-test row that runs the check against the committedci.ymland asserts exit 0, so a poisoning comment fails the self-test loudly instead of reading the gate as broken.Oracle (executed, non-vacuous)
--self-testgrows to 18 rows (exit 0), including the The REQUIRED 'Fuzz smoke' job's target list is compared against nothing; check_fuzz_targets audits only the advisory nightly #406 acceptance criterion — a[[bin]]absent fromfuzz-smokeexits 1 — whose exit differs from the base row (0) on the same tool with a distinct input, the discrimination the advisory-only tool lacked. Mutating_one_smoke_targetto a constant reds the suite (not green-regardless).[[bin]]to the realfuzz/Cargo.tomlmakes the fuzz-smoke check exit 1 (fuzz_new_harness … NOT run by the fuzz-smoke job); the unmodified tree exits 0.rivet validate→ PASS; no broken cross-refs.Artifacts
REQ-GUARD-FUZZ-SMOKE-001(implemented) andTEST-GUARD-FUZZ-SMOKE(with runnablefields.stepsandsatisfies/verifieslinks).human-scopedREQ-GUARD-GATE-EVIDENCE-002is not touched or promoted.Honest scope
Set equality proves declaration parity, not execution — a
fuzz-smokeleg carryingcontinue-on-error: trueorif: falsestill counts as "run". That is a distinct obligation (execution evidence) left to a successor; this closes the list-parity hole #406 names and no more.Closes #406.
🤖 Generated with Claude Code
Generated by Claude Code